#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>


using namespace std;

const string defaultIp = "0.0.0.0";
const int g_num = 1024;
typedef function<void(string&, string&, uint16_t, int)> func;

class udpServer
{
public:
    udpServer(func cb, uint16_t port, const string& ip = defaultIp)
    : _cb(cb),
      _port(port),
      _ip(ip),
      _sockfd(-1)
    {}

    void initServer()
    {
        //创建socket
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd == -1)
        {
            cerr << strerror(errno) << endl;
            exit(1);
        }
        cout << "create socket success " << _sockfd << endl;
        //绑定ip和port
        struct sockaddr_in local;//struct sockaddr分为sockaddr_in和sockaddr_un两种形式
        bzero(&local, sizeof local);
        local.sin_family = AF_INET;//sa_family_t: unsigned short int
        local.sin_port = htons(_port);//将_port转为网络字节序
        //由于云服务器一般对应多个虚拟ip 如果绑定了某个具体的ip 那么就接收不到发送到其他ip的数据
        local.sin_addr.s_addr = inet_addr(_ip.c_str());//将点分十进制字符串转为32位网络字节序
        //local.sin_addr.s_addr = htonl(INADDR_ANY);//绑定任意ip
        int n = bind(_sockfd, (struct sockaddr*)&local, sizeof local);
        if (n == -1)
        {
            cerr << strerror(errno) << endl;
            exit(2);
        }
    }

    void start()
    {
        char buffer[g_num];
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            //收到哪 收多少 谁发的
            ssize_t n = recvfrom(_sockfd, buffer, sizeof buffer - 1, 0, (struct sockaddr*)&peer, &len);
            if (n > 0)
            {
                buffer[n] = 0;
                string clientIp = inet_ntoa(peer.sin_addr);//将32位网络字节序转为点分十进制字符串
                uint16_t clientPort = ntohs(peer.sin_port);
                string message = buffer;
                cout << clientIp << "[" << clientPort << "]#" << message << endl;
                _cb(message, clientIp, clientPort, _sockfd);
            }
        }
    }

private:
    string _ip;
    uint16_t _port;
    int _sockfd;
    func _cb;
};